package com.wdcloud.netlibrary.util;

import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;

import com.facebook.stetho.okhttp3.StethoInterceptor;
import com.google.gson.Gson;
import com.wdcloud.netlibrary.callback.DownloadFileCallback;
import com.wdcloud.netlibrary.callback.DownloadProgressCallback;
import com.wdcloud.netlibrary.callback.NetWorkCallback;
import com.wdcloud.netlibrary.deliver.IDeliver;
import com.wdcloud.netlibrary.deliver.MainThreadDeliver;
import com.wdcloud.netlibrary.deliver.NativeDeliver;
import com.wdcloud.netlibrary.dispatcher.CommonDispatcher;
import com.wdcloud.netlibrary.dispatcher.DownLoadDispatcher;
import com.wdcloud.netlibrary.dispatcher.IDispatcher;
import com.wdcloud.netlibrary.exception.NetWorkException;
import com.wdcloud.netlibrary.intercept.LoggerInterceptor;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.Dispatcher;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 *
 */
public class OkHttpUtil implements HttpEvent {

    public static final String DOWNLOADING_FILE_SUFFIX = ".downloading";
    private static final int BDUSS_CONNECT_TIMEOUT = 60;
    private OkHttpClient client;
    private MainThreadDeliver mMainThreadDeliver;
    private NativeDeliver mNativeDeliver;
    private HashMap<String, List<Cookie>> cookieStore = new HashMap<>();
    private String baseHost = "";
    private Map<String, Object> proxyMap;
    private HashMap<String, String> cookieMap = new HashMap<>();

    public static boolean IS_DEBUG = false;

    private OkHttpUtil() {
        OkHttpClient.Builder builder = new OkHttpClient.Builder().cookieJar(new CookieJar() {
            @Override
            public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
                cookieStore.put(url.host(), cookies);
            }

            @Override
            public List<Cookie> loadForRequest(HttpUrl url) {
                List<Cookie> cookies = cookieStore.get(url.host());
                if (cookies == null) {
                    cookies = new ArrayList<>();
                } else {
                    cookies = new ArrayList<>(cookies);
                }
                if (cookieMap.size() == 0) {
                    return cookies;
                }
                // 循环剔除重复的cookie
                Iterator<Cookie> iterable = cookies.iterator();
                while (iterable.hasNext()) {
                    Cookie cookie = iterable.next();
                    String key = cookie.name();
                    if (cookieMap.containsKey(key)) {
                        iterable.remove();
                    }
                }
                for (Map.Entry<String, String> entry : cookieMap.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    cookies.add(Cookie.parse(url, key + "=" + value));
                }
                cookieStore.put(url.host(), cookies);
                return cookies;
            }
        }).connectTimeout(BDUSS_CONNECT_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(BDUSS_CONNECT_TIMEOUT, TimeUnit.SECONDS)
                .writeTimeout(BDUSS_CONNECT_TIMEOUT, TimeUnit.SECONDS);

        if (IS_DEBUG) {
            builder.addInterceptor(new LoggerInterceptor());
            builder.addNetworkInterceptor(new StethoInterceptor());
        }
        client = builder.build();
        mMainThreadDeliver = new MainThreadDeliver(new Handler(Looper.getMainLooper()));
        mNativeDeliver = new NativeDeliver();
        proxyMap = new HashMap<>();
    }

    private static class Holder {
        public static final OkHttpUtil INSTANCE = new OkHttpUtil();
    }

    public static OkHttpUtil getInstance() {
        return Holder.INSTANCE;
    }

    public OkHttpClient getClient() {
        return this.client;
    }

    @Override
    public void setCookie(String key, String value) {
        if (TextUtils.isEmpty(key)) {
            return;
        }
        cookieMap.put(key, value == null ? "" : value);
    }

    /**
     * 异步请求
     *
     * @param callBuilder
     * @param callback
     * @param <T>
     */
    @Override
    public <T> void enqueue(CommonDispatcher callBuilder, final NetWorkCallback<T> callback) {
        Call call = getRealCall(callBuilder.request);
        final IDeliver deliver = getDeliver(callBuilder);
        if (callback != null) {
            deliver.deliverStart(callback);
        }
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                saveFailedLog(call);
                handleException(e);
                if (call.isCanceled()) {
                    if (callback != null) {
                        deliver.deliverCancel(callback);
                    }
                } else {
                    if (callback != null) {
                        deliver.deliverFail(callback, e);
                    }
                }
            }

            @Override
            public void onResponse(Call call, Response response) {
                try {
                    if (response.isSuccessful()) {
                        saveLog(call, response);
                        if (callback != null) {
                            T t = parseContent(response, callback);
                            deliver.deliverSuccess(callback, t);
                            deliver.deliverComplete(callback);
                        }
                    } else {
                        saveFailedLog(call);
                        if (callback != null) {
                            deliver.deliverFail(callback, new NetWorkException(response.code(), response.message()));
                        }
                    }
                } catch (Exception e) {
                    saveFailedLog(call);
                    handleException(e);
                    if (callback != null) {
                        deliver.deliverFail(callback, e);
                    }
                } catch (Throwable e) {
                    saveFailedLog(call);
                    e.printStackTrace();
                } finally {
                    if (response != null) {
                        response.close();
                    }
                }
            }
        });
    }

    /**
     * 同步请求
     *
     * @param callBuilder
     * @param c
     * @param <T>
     */
    @Override
    public <T> T execute(CommonDispatcher callBuilder, Class<T> c) throws Exception {
        Call call = getRealCall(callBuilder.request);
        Response response = null;
        try {
            response = call.execute();
            if (response.isSuccessful()) {
                saveLog(call, response);
                if (c.isAssignableFrom(InputStream.class)) {
                    return (T) response.body().byteStream();
                }
                String body = response.body().string();
                if (c.isAssignableFrom(String.class)) {
                    return (T) body;
                }

                T t = (T) new Gson().fromJson(body, c);

//                JSONObject jsonObject = JSONObject.parseObject(body);
//                T t = JSON.parseObject(jsonObject.toJSONString(), c);
                return t;
            } else {
                saveFailedLog(call);
                return null;
            }
        } catch (Exception e) {
            saveFailedLog(call);
            handleException(e);
            throw e;
        } catch (Throwable e) {
            saveFailedLog(call);
            e.printStackTrace();
            return null;
        } finally {
            if (response != null) {
                response.close();
            }
        }
    }

    /**
     * 同步请求
     *
     * @param callBuilder
     * @param callback
     * @param <T>
     */
    @Override
    public <T> void execute(CommonDispatcher callBuilder, final NetWorkCallback<T> callback) {
        Call call = getRealCall(callBuilder.request);
        final IDeliver deliver = getDeliver(callBuilder);
        if (callback != null) {
            deliver.deliverStart(callback);
        }
        Response response = null;
        try {
            response = call.execute();
            if (response.isSuccessful()) {
                saveLog(call, response);
                if (callback != null) {
                    T t = parseContent(response, callback);
                    deliver.deliverSuccess(callback, t);
                    deliver.deliverComplete(callback);
                }
            } else {
                saveFailedLog(call);
                if (callback != null) {
                    deliver.deliverFail(callback, new NetWorkException(response.code(), response.message()));
                }
            }
        } catch (Exception e) {
            saveFailedLog(call);
            handleException(e);
            if (callback != null) {
                deliver.deliverFail(callback, e);
            }
        } catch (Throwable e) {
            saveFailedLog(call);
            e.printStackTrace();
        } finally {
            if (response != null) {
                response.close();
            }
        }
    }

    public void saveLog(Call call, Response response) {
        String state = response.isSuccessful() ? "Success" : "Failed";
        String result;

        HashMap<String, String> headsHashMap = new HashMap<>();
        Headers headers = call.request().headers();
        if (null != headers && headers.size() < 0) {
            Set<String> names = headers.names();
            Iterator<String> iterator = names.iterator();
            while (iterator.hasNext()) {
                String name = iterator.next();
                String value = headers.get(name);
                headsHashMap.put(name, value);
            }
        }

        if (response.request().method().equals("POST")) {
            HashMap<String, String> objectObjectHashMap = new HashMap<>();
            if (call.request().body() instanceof FormBody) {
                for (int i = 0; i < ((FormBody) call.request().body()).size(); i++) {
                    objectObjectHashMap.put(((FormBody) call.request().body()).encodedName(i),
                            ((FormBody) call.request().body()).encodedValue(i));
                }
            }
            result = "{"
                    + "\"state\":" + "\"" + state + "\""
                    + ",\"method\":" + "\"" + response.request().method() + "\""
                    + ",\"headers\":" + "\"" + headsHashMap.toString() + "\""
                    + ",\"url\":" + "\"" + response.request().url() + "?" + objectObjectHashMap.toString() + "\""
                    + ",\"time\":" + "\"" + System.currentTimeMillis() + "\""
                    + '}';
        } else {
            result = "{"
                    + "\"state\":" + "\"" + state + "\""
                    + ",\"method\":" + "\"" + response.request().method() + "\""
                    + ",\"headers\":" + "\"" + headsHashMap.toString() + "\""
                    + ",\"url\":" + "\"" + response.request().url() + "\""
                    + ",\"time\":" + "\"" + System.currentTimeMillis() + "\""
                    + '}';
        }


        RequestUtil.saveRequestToLocalFile(result);
    }

    public void saveFailedLog(Call call) {
        String result;
        HashMap<String, String> headsHashMap = new HashMap<>();
        Headers headers = call.request().headers();
        if (null != headers && headers.size() < 0) {
            Set<String> names = headers.names();
            Iterator<String> iterator = names.iterator();
            while (iterator.hasNext()) {
                String name = iterator.next();
                String value = headers.get(name);
                headsHashMap.put(name, value);
            }
        }
        if (call.request().method().equals("POST")) {
            HashMap<String, String> objectObjectHashMap = new HashMap<>();
            if (call.request().body() instanceof FormBody) {
                for (int i = 0; i < ((FormBody) call.request().body()).size(); i++) {
                    objectObjectHashMap.put(((FormBody) call.request().body()).encodedName(i),
                            ((FormBody) call.request().body()).encodedValue(i));
                }
            }

            result = "{"
                    + "\"state\":" + "\"" + "Failed" + "\""
                    + ",\"method\":" + "\"" + call.request().method() + "\""
                    + ",\"headers\":" + "\"" + headsHashMap.toString() + "\""
                    + ",\"url\":" + "\"" + call.request().url() + "?" + objectObjectHashMap + "\""
                    + ",\"time\":" + "\"" + System.currentTimeMillis() + "\""
                    + '}';
        } else {
            result = "{"
                    + "\"state\":" + "\"" + "Failed" + "\""
                    + ",\"method\":" + "\"" + call.request().method() + "\""
                    + ",\"headers\":" + "\"" + headsHashMap.toString() + "\""
                    + ",\"url\":" + "\"" + call.request().url() + "\""
                    + ",\"time\":" + "\"" + System.currentTimeMillis() + "\""
                    + '}';
        }
        RequestUtil.saveRequestToLocalFile(result);
    }

    /**
     * 下载文件
     *
     * @param callBuilder
     * @param callback
     */
    @Override
    public void downloadFile(final DownLoadDispatcher callBuilder, final DownloadFileCallback callback) {
        Call call = getRealCall(callBuilder.request);
        final IDeliver deliver = getDeliver(callBuilder);
        if (callback != null) {
            deliver.deliverStart(callback);
        }
        try {
            File dirFile = new File(callBuilder.dir);
            if (!dirFile.exists()) {
                if (!dirFile.mkdirs()) {
                    throw new NetWorkException("文件夹创建失败，请检查路径和权限");
                }

            }
            File aimFile = new File(dirFile, callBuilder.fileName + DOWNLOADING_FILE_SUFFIX);
            if (aimFile.exists()) {
                aimFile.delete();
            }
            aimFile.createNewFile();
        } catch (Exception e) {
            if (callback != null) {
                deliver.deliverFail(callback, e);
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                saveFailedLog(call);
                handleException(e);
                if (call.isCanceled()) {
                    if (callback != null) {
                        deliver.deliverCancel(callback);
                    }
                } else {
                    if (callback != null) {
                        deliver.deliverFail(callback, e);
                    }
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                InputStream is = null;
                FileOutputStream fos = null;
                long totalLength = 0;
                long currentLen = 0;
                try {
                    if (response.isSuccessful()) {
                        saveLog(call, response);
                        totalLength = response.body().contentLength();
                        if (totalLength <= 0) {
                            totalLength = -1;
                        }

                        File dirFile = new File(callBuilder.dir);
                        File aimFile = new File(dirFile, callBuilder.fileName + DOWNLOADING_FILE_SUFFIX);
                        is = response.body().byteStream();
                        fos = new FileOutputStream(aimFile);

                        byte[] buf = new byte[2048];
                        int len;
                        long startTime = System.currentTimeMillis();
                        int i = 1;
                        while ((len = is.read(buf)) != -1) {
                            fos.write(buf, 0, len);
                            if (callback != null) {
                                if (callback instanceof DownloadProgressCallback) {
                                    currentLen += len != -1 ? len : 0;
                                    long currentTime = System.currentTimeMillis();
                                    // 分两种情况处理,1.可以获取到总长度2.不可以获取到总长度
                                    if (totalLength == -1) {
                                        if (currentTime - startTime > 1000) {
                                            startTime = currentTime;
                                            if (i == 100) {
                                                i = 99;
                                            }
                                            deliver.deliverProgress((DownloadProgressCallback) callback,
                                                    currentLen, totalLength, i++);
                                        }
                                    } else {
                                        if (currentTime - startTime > 300) {
                                            startTime = currentTime;
                                            handleProgress(currentLen, totalLength, deliver,
                                                    (DownloadProgressCallback) callback);
                                        }
                                    }
                                }
                            }
                            fos.flush();
                        }
                        aimFile.renameTo(new File(dirFile, callBuilder.fileName));
                        if (callback != null) {
                            // 下载完成
                            if (callback instanceof DownloadProgressCallback) {
                                deliver.deliverProgress((DownloadProgressCallback) callback,
                                        currentLen, totalLength, 100);
                            }
                            deliver.deliverComplete(callback);
                        }
                    } else {
                        saveFailedLog(call);
                        if (callback != null) {
                            deliver.deliverFail(callback, new NetWorkException(response.code(), response.message()));
                        }
                    }
                } catch (Exception e) {
                    saveFailedLog(call);
                    handleException(e);
                    if (callback != null) {
                        if (e instanceof SocketException) {
                            if (callback instanceof DownloadProgressCallback) {
                                handleProgress(currentLen, totalLength, deliver,
                                        (DownloadProgressCallback) callback);
                            }
                            deliver.deliverCancel(callback);
                        } else {
                            deliver.deliverFail(callback, e);
                        }
                    }
                } catch (Throwable e) {
                    saveFailedLog(call);
                    e.printStackTrace();
                } finally {
                    if (fos != null) {
                        fos.close();
                    }

                    if (is != null) {
                        is.close();
                    }

//                    IOUtils.close(fos);
//                    IOUtils.close(is);
                    if (response != null) {
                        response.close();
                    }
                }
            }
        });
    }

    /**
     * 断点下载
     *
     * @param callBuilder
     * @param callback
     */
    @Override
    public void downloadFileWithMemory(final DownLoadDispatcher callBuilder, final DownloadFileCallback callback) {
        Call call = getRealCall(callBuilder.request);
        final IDeliver deliver = getDeliver(callBuilder);
        if (callback != null) {
            deliver.deliverStart(callback);
        }
        long startIndex = 0;
        try {
            // 检查下载文件，并确定下载开始位置
            File dirFile = new File(callBuilder.dir);
            if (!dirFile.exists()) {
                if (!dirFile.mkdirs()) {
                    throw new NetWorkException("文件夹创建失败，请检查路径和权限");
                }

            }
            File aimFile = new File(dirFile, callBuilder.fileName + DOWNLOADING_FILE_SUFFIX);
            if (aimFile.exists()) {
                // 防止文件已经写完，rename 失败的情况，如果从文件末尾请求会报错 Range 失败
                startIndex = aimFile.length();
                if (startIndex > 0) {
                    startIndex -= 1;
                }
            } else {
                aimFile.createNewFile();
                startIndex = 0;
            }
            realDownload(call, startIndex, callback, deliver, callBuilder);
        } catch (Exception e) {
            saveFailedLog(call);
            if (callback != null) {
                deliver.deliverFail(callback, e);
            }
        } catch (Throwable e) {
            saveFailedLog(call);
            e.printStackTrace();
        }
    }

    /**
     * 真正的下载逻辑
     *
     * @param call
     * @param startIndex
     * @param callback
     * @param deliver
     * @param callBuilder
     */
    private void realDownload(Call call, final long startIndex,
                              final DownloadFileCallback callback, final IDeliver deliver,
                              final DownLoadDispatcher callBuilder) {
        // 获取到range长度，执行下载
        Request newRequest = call.request().newBuilder()
                .header("Range", "bytes=" + startIndex + "-")
                .build();
        Call newCall = getClient().newCall(newRequest);
        newCall.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                saveFailedLog(call);
                handleException(e);
                if (call.isCanceled()) {
                    if (callback != null) {
                        deliver.deliverCancel(callback);
                    }
                } else {
                    if (callback != null) {
                        deliver.deliverFail(callback, e);
                    }
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                InputStream is = null;
                RandomAccessFile randomAccessFile = null;
                long current = startIndex;
                long totalLength = -1;
                try {
                    if (response.isSuccessful()) {
                        saveLog(call, response);
                        File dirFile = new File(callBuilder.dir);
                        File aimFile = new File(dirFile, callBuilder.fileName + DOWNLOADING_FILE_SUFFIX);
                        is = response.body().byteStream();
                        randomAccessFile = new RandomAccessFile(aimFile, "rwd");
                        randomAccessFile.seek(startIndex);

                        // 确认下载文件总长度
                        long contentLength = response.body().contentLength();
                        if (contentLength <= 0) {
                            totalLength = -1;
                        } else {
                            totalLength = startIndex + contentLength;
                        }
                        byte[] buf = new byte[2048];
                        int len;
                        long startTime = System.currentTimeMillis();
                        int i = 1;
                        while ((len = is.read(buf)) != -1) {
                            randomAccessFile.write(buf, 0, len);
                            if (callback != null) {
                                if (callback instanceof DownloadProgressCallback) {
                                    current += len != -1 ? len : 0;
                                    long currentTime = System.currentTimeMillis();
                                    // 分两种情况处理,1.可以获取到总长度2.不可以获取到总长度
                                    if (totalLength == -1) {
                                        if (currentTime - startTime > 1000) {
                                            startTime = currentTime;
                                            if (i == 100) {
                                                i = 99;
                                            }
                                            deliver.deliverProgress((DownloadProgressCallback) callback,
                                                    current, totalLength, i++);
                                        }
                                    } else {
                                        if (currentTime - startTime > 300) {
                                            startTime = currentTime;
                                            handleProgress(current, totalLength, deliver,
                                                    (DownloadProgressCallback) callback);
                                        }
                                    }
                                }
                            }
                        }
                        aimFile.renameTo(new File(dirFile, callBuilder.fileName));
                        if (callback != null) {
                            // 下载完成
                            if (callback instanceof DownloadProgressCallback) {
                                deliver.deliverProgress((DownloadProgressCallback) callback,
                                        current, totalLength, 100);
                            }
                            deliver.deliverComplete(callback);
                        }
                    } else {
                        saveFailedLog(call);
                        if (callback != null) {
                            deliver.deliverFail(callback,
                                    new NetWorkException(response.code(), response.message()));
                        }
                    }
                } catch (Exception e) {
                    saveFailedLog(call);
                    handleException(e);
                    if (callback != null) {
                        if (e instanceof SocketException) {
                            if (callback instanceof DownloadProgressCallback) {
                                handleProgress(current, totalLength, deliver,
                                        (DownloadProgressCallback) callback);
                            }
                            deliver.deliverCancel(callback);
                        } else {
                            deliver.deliverFail(callback, e);
                        }
                    }
                } catch (Throwable e) {
                    saveFailedLog(call);
                    e.printStackTrace();
                } finally {

                    if (randomAccessFile != null) {
                        randomAccessFile.close();
                    }

                    if (is != null) {
                        is.close();
                    }

//                    IOUtils.close(randomAccessFile);
//                    IOUtils.close(is);

                    if (response != null) {
                        response.close();
                    }
                }
            }
        });
    }

    @Override
    public void cancel(Object o) {
        Dispatcher dis = OkHttpUtil.getInstance().getClient().dispatcher();
        synchronized (dis) {
            for (Call call : dis.queuedCalls()) {
                if (call.request().tag().equals(o)) {
                    call.cancel();
                }
            }

            for (Call call : dis.runningCalls()) {
                if (call.request().tag().equals(o)) {
                    call.cancel();
                }
            }
        }
    }

    /**
     * 设置默认host
     *
     * @param host
     * @return
     */
    public OkHttpUtil setBaseHost(String host) {
        if (!TextUtils.isEmpty(host)) {
            this.baseHost = host;
        }
        return this;
    }

    /**
     * 设置代理
     *
     * @param map
     * @return
     */
    public OkHttpUtil setProxy(Map<String, Object> map) {
        if (map != null) {
            this.proxyMap = map;
        }
        return this;
    }

    /**
     * 获取代理
     *
     * @return
     */
    private String getProxy(String url) {
        for (Map.Entry<String, Object> entry : proxyMap.entrySet()) {
            if (url.startsWith(entry.getKey())) {
                url = url.replace(entry.getKey(), (String) entry.getValue());
                break;
            }
        }
        return url;
    }

    /**
     * 构建call
     *
     * @param request
     * @return
     */
    public Call getRealCall(Request request) {
        HttpUrl httpUrl = request.url();
        String s = httpUrl.toString();
        String realUrl = getProxy(s.trim());
        return getClient().newCall(request.newBuilder().url(realUrl).build());
    }

    /**
     * 外部设置httpclient
     *
     * @param client
     * @return
     */
    public OkHttpUtil setClient(OkHttpClient client) {
        if (client != null) {
            this.client = client;
        }
        return this;
    }

    /**
     * 添加应用拦截器
     *
     * @param interceptor
     * @return
     */
    public OkHttpUtil addInterceptor(Interceptor interceptor) {
        if (interceptor != null) {
            this.client = this.client.newBuilder().addInterceptor(interceptor).build();
        }
        return this;
    }

    /**
     * 添加网络拦截器
     *
     * @param interceptor
     * @return
     */
    public OkHttpUtil addNetworkInterceptor(Interceptor interceptor) {
        if (interceptor != null) {
            this.client = this.client.newBuilder().addNetworkInterceptor(interceptor).build();
        }
        return this;
    }

    /**
     * 请求体解析
     *
     * @param response
     * @param callback
     * @param <T>
     */
    private <T> T parseContent(Response response, NetWorkCallback<T> callback) throws Exception {

        Type finalNeedType;

        T t = null;

        String body = null;

        final Type[] types = callback.getClass().getGenericInterfaces();
        if (MethodHandler(types) == null || MethodHandler(types).size() == 0) {
            finalNeedType = ((ParameterizedType) callback.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
            if (finalNeedType == null) {
                return null;
            }
        } else {
            finalNeedType = MethodHandler(types).get(0);
        }


        if (finalNeedType instanceof ParameterizedType) {//范型
            byte[] bytes = response.body().bytes();
            body = new String(bytes);
//            JSONObject jsonObject = JSONObject.parseObject(body);

            t = (T) new Gson().fromJson(body, finalNeedType);


//            final Class<T> entityClass = (Class<T>) finalNeedType;

//            JSONObject.parseObject(jsonObject, new TypeReference<List<String>>(){});

//            t = JSON.parseObject(jsonObject.toJSONString(), finalNeedType);
        } else {
            Class<T> entityClass = (Class<T>) finalNeedType;

            if (entityClass.isAssignableFrom(InputStream.class)) {
                return (T) response.body().byteStream();
            }
            body = response.body().string();
            if (entityClass.isAssignableFrom(String.class)) {
                return (T) body;
            }

            t = (T) new Gson().fromJson(body, finalNeedType);

//            JSONObject jsonObject = JSONObject.parseObject(body);
//            t = JSON.parseObject(jsonObject.toJSONString(), entityClass);
        }

        return t;
    }

    private void handleException(Exception e) {
        if (e instanceof SocketTimeoutException
                || e instanceof UnknownHostException) {
            client.connectionPool().evictAll();
        }
    }

    /**
     * MethodHandler
     */
    private List<Type> MethodHandler(Type[] types) {
        List<Type> needtypes = new ArrayList<>();
        Type needParentType = null;

        for (Type paramType : types) {
            System.out.println("  " + paramType);
            // if Type is T
            if (paramType instanceof ParameterizedType) {
                Type[] parentypes = ((ParameterizedType) paramType).getActualTypeArguments();
                for (Type childtype : parentypes) {
                    needtypes.add(childtype);
                    //needParentType = childtype;
                    if (childtype instanceof ParameterizedType) {
                        Type[] childtypes = ((ParameterizedType) childtype).getActualTypeArguments();
                        for (Type type : childtypes) {
                            needtypes.add(type);
                            //needChildType = type;
                        }
                    }
                }
            }
        }
        return needtypes;
    }


    private long deliverProgress(long totalLength, long current,
                                 long startTime, int i,
                                 IDeliver deliver, DownloadProgressCallback callback) {
        long currentTime = System.currentTimeMillis();
        // 分两种情况处理,1.可以获取到总长度2.不可以获取到总长度
        if (totalLength == -1) {
            if (currentTime - startTime > 1000) {
                startTime = currentTime;
                if (i == 100) {
                    i = 99;
                }
                deliver.deliverProgress(callback, current, totalLength, i++);
            }
        } else {
            if (currentTime - startTime > 300) {
                startTime = currentTime;
                handleProgress(current, totalLength, deliver, callback);
            }
        }
        return startTime;
    }

    private void handleProgress(long current, long totalLength, IDeliver deliver,
                                DownloadProgressCallback callback) {
        int progress = 0;
        if (totalLength > 0) {
            progress = (int) (current * 100 / totalLength);
        }
        deliver.deliverProgress(callback,
                current, totalLength, progress);
    }

    private IDeliver getDeliver(IDispatcher dispatcher) {
        IDeliver deliver;
        if (dispatcher.isLocal()) {
            deliver = mNativeDeliver;
        } else {
            deliver = mMainThreadDeliver;
        }
        return deliver;
    }
}
